package com.myway.core.base.db.impl;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.*;

import com.myway.core.base.page.PaginationInfo;

import com.myway.core.base.db.BaseDao;
import com.myway.dto.utils.DTOPagedList;

@SuppressWarnings({"deprecation","unchecked","rawtypes"})
public class BaseDaoImpl<B extends Serializable>  implements BaseDao<B> {
	private Class<B> queryClass;
	private String defaultOrder = "id";
	private boolean defaultOrderAsc = true;
	private static int DEFAULT_PAGE_SIZE = 10; // 默认每页显示的记录条数
	@PersistenceContext
	private EntityManager entityManager;

	public BaseDaoImpl(){
	}
	public BaseDaoImpl(Class<B> queryClass) {
		super();
		this.queryClass = queryClass;
	}
	
	public B getNewInstance() {
		try {
			return getQueryClass().newInstance();
		} catch (InstantiationException e) {
			throw new RuntimeException("Error creating new instance of : " + getQueryClass().getName(), e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException("Error creating new instance of : " + getQueryClass().getName(), e);
		}
	}

	/* (non-Javadoc)
	 * @see com.euair.dao.BaseDao#findById(java.lang.Object)
	 */
	public B find(Object id) {
		return (B) entityManager.find(queryClass, id);
	}
	

	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#findByNamedQuery(java.lang.String, java.lang.Object[])
	 */
	public List<B> findByNamedQuery(String queryName, Object... objects) {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#findByNamedQueryAndNamedParams(java.lang.String, java.utils.Map)
	 */
	public List<B> findByNamedQueryAndNamedParams(String queryName, Map<String, Object> paramMap) {
		return null;
	}
	
	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#getReference(java.lang.Object)
	 */
	public B getReference(Object id) {
		return entityManager.getReference(queryClass, id);
	}

	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#persist(B)
	 */
	public void persist(B obj) {
		entityManager.persist(obj);
	}

	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#merge(B)
	 */
	public void merge(B obj) {
		entityManager.merge(obj);
	}
	
	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#refresh(B)
	 */
	public void refresh(B obj) {
		entityManager.refresh(obj);
	}

	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#remove(B)
	 */
	public void remove(B obj) {
		entityManager.remove(obj);
	}

	@Override
	public void lock(B obj, LockModeType type) {

	}

	@Override
	public List<B> super_hql_listQuery(String hql, Object... params) {
		return null;
	}


	protected List<B> getPageOfData(Query query, PaginationInfo pageInfo) {
		if (pageInfo.getFirstRow() != -1) {
			query.setFirstResult(pageInfo.getFirstRow());
		}

		if (pageInfo.getMaxResults() != -1) {
			query.setMaxResults(pageInfo.getMaxResults());
		}

		return addPaginationInfo(query, pageInfo).getResultList();
	}

	protected Query addPaginationInfo(Query query, PaginationInfo pageInfo) {
		if (pageInfo.getFirstRow() != -1) {
			query.setFirstResult(pageInfo.getFirstRow());
		}

		if (pageInfo.getMaxResults() != -1) {
			query.setMaxResults(pageInfo.getMaxResults());
		}

		return query;
	}
	

	public DTOPagedList<B> super_hql_pagedQuery(final String hql, Integer currentPageNum,Integer pageSize,final Object... values) {
		DTOPagedList<B> dto=new DTOPagedList<B>();
		if(currentPageNum==null || currentPageNum<=0){
			currentPageNum=1;
		}
		if(pageSize==null || pageSize<=0){
			pageSize=DEFAULT_PAGE_SIZE;
		}

		final int firstResult=(currentPageNum-1)*pageSize;
		final int maxResults=pageSize;
		dto.setMaxPageNumber(currentPageNum*pageSize);
		dto.setCurrentPageNumber(firstResult);

		// Count查询
		String countQueryString = " select count (*) " + removeSelect(removeOrders(removeGroupBy(hql)));
		int totalCount = 0;


		if(totalCount==0){
			dto.setList(Collections.EMPTY_LIST);
			dto.setTotalResultCount(0l);
			return dto;
		}
		dto.setTotalResultCount((long)totalCount);

		return dto;
	}

	@Override
	public int super_sql_update(String sql, Object... params) {
		return 0;
	}

	@Override
	public int super_sql_count(String sql, Object... params) {
		return 0;
	}


	/***
	 * SQL查询
	 * @param sql 查询sql语句
	 * @param params sql语句中的查询列条件
	 * @return
	 */
	public List<Map<String, Object>> super_sql_listQuery(String sql,Object... params) {
		return null;
	}
	
	/***
	 * SQL查询
	 * @param cb 结果返回值封装类
	 * @param sql 查询sql语句
	 * @param params sql语句中的查询列条件
	 * @return
	 */
	public List<B> superSqlListQuery(String sql,Object... params) {
		return null;
	}
	
	/***
	 * SQL查询
	 * @param cb 结果返回值封装类
	 * @param sql 查询sql语句
	 * @param params sql语句中的查询列条件
	 * @return
	 */
	public List<B> super_sql_listQuery(Class<B> rm,String sql,Object... params) {
		return null;
	}
	
	public DTOPagedList<B> super_sql_listQuery(String sql, Integer currentPageNum,Integer pageSize,Object... params) {
		return super_sql_listQuery(queryClass,sql,currentPageNum,pageSize,params);
	}
	
	public DTOPagedList<B> super_sql_listQuery(Class<B> rm,String sql, Integer currentPageNum,Integer pageSize,Object... params) {
		
		DTOPagedList<B> dto=new DTOPagedList<B>();
		if(currentPageNum==null || currentPageNum<=0){
			currentPageNum=1;
		}
		if(pageSize==null || pageSize<=0){
			pageSize=DEFAULT_PAGE_SIZE;
		}
		final int firstResult=(currentPageNum-1)*pageSize;
		final int maxResults=currentPageNum*pageSize;
		dto.setMaxPageNumber(maxResults);
		dto.setCurrentPageNumber(firstResult);
		
		// Count查询
		String countQuerySql =getCountQuerySql(sql);
		int totalCount=super_sql_count(countQuerySql, params);
		if(totalCount==0){
			dto.setList(Collections.EMPTY_LIST);
			dto.setTotalResultCount(0l);
			return dto;
		}
		dto.setTotalResultCount((long)totalCount);
		String querySql=createSqlQuery("ora", sql, firstResult, maxResults);
		dto.setList(super_sql_listQuery(rm, querySql,params));
		return dto;
	}
	
	/***
	 * 获取sql count查询语句
	 * @param sql
	 * @return
	 */
	private String getCountQuerySql(String sql){
		String querySql=" select count (*) ";
		if(sql.toUpperCase().indexOf(" UNION ")>0){
			querySql+=" from ("+sql+") pTable_ ";
		}else{
			querySql+=removeSelect(removeOrders(removeGroupBy(sql)));
		}
		return querySql;
	}
	
	 /**
	 * 去除hql中的group by语句
	 * @param hql
	 * @return
	 */
	private String removeGroupBy(String hql) {
		Pattern p = Pattern.compile("group\\s*by[\\w|\\W|\\s|\\S]*",Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(hql);
		StringBuffer sb = new StringBuffer();
		while (m.find()) {
			m.appendReplacement(sb, "");
		}
		m.appendTail(sb);
		return sb.toString();
	}
	
	/**
	 * 去除hql中的order by语句
	 * @param hql
	 * @return
	 */
	private static String removeOrders(String hql) {
		Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]",Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(hql);
		int i=0;
		int index=-1;
		while (m.find()) {
			i++;
			index=m.start();
		}
		if(i>0){
			hql=hql.substring(0, index);
		}
		return hql;
	}
	
	private static String removeSelect(final String hql) {
		final int beginPos = hql.toLowerCase().indexOf("from");
		return hql.substring(beginPos);
	}
	
	/**
	 * 创建查询脚本(Sql)
	 * @param type
	 *            ora: oracle <br/>
	 *            mss: microsoft sql server <br/>
	 *            mys: my sql <br/>
	 *            db2: ibm db2<br/>
	 * @param sql
	 * @param pageStart
	 * @param pageEnd
	 * @return
	 */
	public String createSqlQuery(String type, String sql, int pageStart,
			int pageEnd) {

		if ("ora".equals(type)) {
			sql = "select * from (select pTable_.*, rownum rNum_ from (" + sql
					+ ") pTable_ where rownum<=" + pageEnd + ") where rNum_>"
					+ pageStart;
		} else if ("mss".equals(type)) {

		} else if ("mys".equals(type)) {

		} else if ("db2".equals(type)) {
			sql = "select * from (select *, rownumber() ROW_NEXT from (" + sql
					+ ") where ROW_NEXT between " + pageStart + " and "
					+ pageEnd;
		}
		return sql;
	}
	
	
	
	
	
	public Class<B> getQueryClass() {
		return queryClass;
	}

	public void setQueryClass(Class<B> queryClass) {
		this.queryClass = queryClass;
	}

	public String getDefaultOrder() {
		return defaultOrder;
	}

	public void setDefaultOrder(String defaultOrder) {
		this.defaultOrder = defaultOrder;
	}

	public boolean isDefaultOrderAsc() {
		return defaultOrderAsc;
	}

	public void setDefaultOrderAsc(boolean defaultOrderAsc) {
		this.defaultOrderAsc = defaultOrderAsc;
	}	
}
